home *** CD-ROM | disk | FTP | other *** search
- /* Internet FTP client (interactive user)
- * Copyright 1991 Phil Karn, KA9Q
- */
- /* Mods by G1EMM and PA0GRI */
- /* modifications for encrypted password by ik1che 900419 */
- /* added "resume" and "rput" commands for interrupted file transfers
- * by iw0cnb 15 Feb 92 */
-
- /* VIEW command added by Simon G1FHY. Mod by Paul@wolf.demon.co.uk */
- #include "global.h"
- #include "commands.h"
- #include "files.h"
- #ifdef UNIX
- #include <sys/stat.h>
- #endif
- #include "mbuf.h"
- #include "session.h"
- #ifdef MSDOS
- #include "ctype.h"
- #else
- #include "socket.h"
- #endif
- #include "netuser.h"
- #ifdef LZW
- #include "lzw.h"
- #endif
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: ftpcli.c,v 1.28 1997/08/19 01:19:22 root Exp root $";
- #endif
-
- #define FTPDIRBUF 256
-
- #ifdef ALLSESSIONS
- static int compsub (struct ftpcli * ftp, char *localname, char *remotename);
- static int txlate (int argc, char *argv[], void *p, const char *substr, int parm);
- static int doascii (int argc, char *argv[], void *p);
- static int dobatch (int argc, char *argv[], void *p);
- static int dobinary (int argc, char *argv[], void *p);
- static int docompare (int argc, char *argv[], void *p);
- static int doftpcd (int argc, char *argv[], void *p);
- static int doftpcdup (int argc, char *argv[], void *p);
- static int doftpdel (int argc, char *argv[], void *p);
- static int doget (int argc, char *argv[], void *p);
- static int dohash (int argc, char *argv[], void *p);
- static int doverbose (int argc, char *argv[], void *p);
- static int dolist (int argc, char *argv[], void *p);
- static int dols (int argc, char *argv[], void *p);
- static int domd5 (int argc, char *argv[], void *p);
- #ifdef ALLSESSIONS
- static int doldir (int argc, char *argv[], void *p);
- #endif
- static int dolcd (int argc, char *argv[], void *p);
- static int dolmkdir (int argc, char *argv[], void *p);
- static int dolrename (int argc, char *argv[], void *p);
- static int dolrmdir (int argc, char *argv[], void *p);
- #ifdef LZW
- static int doftplzw (int argc, char *argv[], void *p);
- #endif
- static int domcompare (int argc, char *argv[], void *p);
- static int domkdir (int argc, char *argv[], void *p);
- static int domget (int argc, char *argv[], void *p);
- static int domput (int argc, char *argv[], void *p);
- static int doput (int argc, char *argv[], void *p);
- static int dopwd (int argc, char *argv[], void *p);
- static int doftphelp (int argc, char *argv[], void *p);
- static int doquit (int argc, char *argv[], void *p);
- static int dormdir (int argc, char *argv[], void *p);
- static int doftprename (int argc, char *argv[], void *p);
- static int doresume (int argc, char *argv[], void *p);
- static int dorput (int argc, char *argv[], void *p);
- static int dotype (int argc, char *argv[], void *p);
- static int doftpview (int argc, char *argv[], void *p);
- static int ftpgetline (struct session * sp, const char *prompt, char *buf, int n);
- static int getresp (struct ftpcli * ftp, int mincode);
- static int doftpupdate (int argc, char *argv[], void *p);
- static long getsub (struct ftpcli * ftp, const char *command, const char *remotename,
- char *localname);
- static long putsub (struct ftpcli * ftp, char *remotename, char *localname, int putr);
- static void sendport (int s, struct sockaddr_in * thesocket);
- static char *ftpcli_login (struct ftpcli * ftp, char *host);
- #ifdef LZW
- static int synclzw (register struct ftpcli * ftp);
- #endif
- #ifdef MSDOS
- extern void strrev (char *str);
- #endif
-
- static char Notsess[] = "Not an FTP session!\n";
- static int Ftp_type = ASCII_TYPE;
- static int Ftp_logbsize = 8;
-
- static struct cmds Ftpcmds[] =
- {
- { "", donothing, 0, 0, NULLCHAR },
- { "?", doftphelp, 0, 0, NULLCHAR },
- { "append", doput, 0, 2, "append <localfile> <remotefile>" },
- { "ascii", doascii, 0, 0, NULLCHAR },
- { "batch", dobatch, 0, 0, NULLCHAR },
- { "binary", dobinary, 0, 0, NULLCHAR },
- { "bye", doquit, 0, 0, NULLCHAR },
- { "cd", doftpcd, 0, 2, "cd <directory>" },
- { "cdup", doftpcdup, 0, 0, NULLCHAR },
- { "compare", docompare, 0, 2, "compare <remotefile> [<localfile>]" },
- { "del", doftpdel, 0, 2, "del <remotefile>" },
- { "dir", dolist, 0, 0, NULLCHAR },
- { "exit", doquit, 0, 0, NULLCHAR },
- { "get", doget, 0, 2, "get <remotefile> <localfile>" },
- { "hash", dohash, 0, 0, NULLCHAR },
- { "help", doftphelp, 0, 0, NULLCHAR },
- { "lcd", dolcd, 0, 1, NULLCHAR },
- #ifdef ALLSESSIONS
- { "ldir", doldir, 0, 1, NULLCHAR },
- #endif
- { "list", dolist, 0, 0, NULLCHAR },
- { "lmkdir", dolmkdir, 0, 2, "lmkdir <local Directory>" },
- { "lrename", dolrename, 0, 3, "lrename <oldname> <newname>" },
- { "lrmdir", dolrmdir, 0, 2, "lrmdir <local Directory>" },
- { "ls", dols, 0, 0, NULLCHAR },
- #ifdef LZW
- { "lzw", doftplzw, 0, 0, NULLCHAR },
- #endif
- { "mcompare", domcompare, 0, 2, "mcompare <file> [<file> ...]" },
- { "md", domkdir, 0, 2, "md <directory>" },
- { "md5", domd5, 0, 2, "md5 <file>" },
- { "mget", domget, 0, 2, "mget <file> [<file> ...]" },
- { "mkdir", domkdir, 0, 2, "mkdir <directory>" },
- { "mput", domput, 0, 2, "mput <file> [<file> ...]" },
- { "nlist", dols, 0, 0, NULLCHAR },
- { "nlst", dols, 0, 0, NULLCHAR },
- { "put", doput, 0, 2, "put <localfile> <remotefile>" },
- { "pwd", dopwd, 0, 0, NULLCHAR },
- { "quit", doquit, 0, 0, NULLCHAR },
- { "rename", doftprename, 0, 3, "rename <oldname> <newname>" },
- { "resume", doresume, 0, 2, "resume <remotefile> <localfile>" },
- { "rmdir", dormdir, 0, 2, "rmdir <directory>" },
- { "rput", dorput, 0, 2, "rput <localfile> <remotefile>" },
- { "type", dotype, 0, 0, NULLCHAR },
- { "update", doftpupdate, 0, 0, NULLCHAR },
- { "verbose", doverbose, 0, 0, NULLCHAR },
- { "view", doftpview, 0, 2, "view <remotefile>"},
- { NULLCHAR, NULLFP ((int, char **, void *)),
- 0, 0, NULLCHAR }
- };
-
-
- int
- doftphelp (int argc, char *argv[], void *p OPTIONAL)
- {
- dohelper ("FTP commands:\n", &Ftpcmds[1], NULLCHAR, (argv[0][0] == '?' && argc == 1) ? NULLCHAR : FTPHelp, (argc == 2) ? argv[1] : NULLCHAR);
- return 0;
- }
-
-
- /* Handle top-level FTP command */
- int
- doftp (int argc, char *argv[], void *p OPTIONAL)
- {
- struct session *sp;
- struct ftpcli ftp;
- struct sockaddr_in fsocket;
- int resp, vsave;
- char *buf, *bufsav, *un;
- char const *cp;
- char prmt[40];
- #ifdef notyet
- char l[17];
- #endif
- int control;
- static FILE *fp1 = NULLFILE;
- struct cur_dirs dirs;
- int pauseonexit = 0;
-
- /*Make sure this comes from console - WG7J*/
- if (Curproc->input != Command->input)
- return 0;
-
- /* Allocate a session control block */
- if ((sp = newsession (argv[1], FTP, 0)) == NULLSESSION) {
- tputs (TooManySessions);
- return 1;
- }
- memset ((char *) &ftp, 0, sizeof (ftp));
- ftp.control = ftp.data = -1;
- ftp.verbose = V_BYTE; /* changed to ver 4 default - KO4KS */
- ftp.type = (char) Ftp_type;
- ftp.logbsize = Ftp_logbsize;
-
- sp->cb.ftp = &ftp; /* Downward link */
- ftp.session = sp; /* Upward link */
-
- ftp.curdirs = &dirs;
-
- fsocket.sin_family = AF_INET;
- fsocket.sin_port = IPPORT_FTP;
-
- tprintf ("Resolving %s... ", sp->name);
- if ((fsocket.sin_addr.s_addr = resolve (sp->name)) == 0) {
- tprintf (Badhost, sp->name);
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- return 1;
- }
- /* Open the control connection */
- if ((control = sp->s = ftp.control = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
- tputs (Nosock);
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- return 1;
- }
- (void) sockmode (sp->s, SOCK_ASCII);
- (void) setflush (sp->s, -1); /* Flush output only when we call getresp() */
- tprintf ("Trying %s...\n", psocket ((struct sockaddr *) &fsocket));
- tprintf ("Local Directory - %s\n", init_dirs (&dirs));
- if (connect (control, (char *) &fsocket, sizeof (fsocket)) == -1)
- goto quit;
- tprintf ("FTP session %u connected to %s\n", (unsigned) (sp - Sessions),
- sp->name);
-
- /* Wait for greeting from server */
- resp = getresp (&ftp, 200);
-
- if (resp >= 400)
- goto quit;
- if ((un = getenv ("LOGNAME")) == NULLCHAR)
- un = getenv ("USER");
- if (un != NULLCHAR)
- sprintf (prmt, "Enter user name (%s): ", un);
- else
- sprintf (prmt, "Enter user name: ");
- /* Now process responses and commands */
- buf = mallocw (LINELEN);
-
- /*lint -esym(668, fp1) */
- if (argc > 2) {
- if ((fp1 = fopen (argv[2], READ_TEXT)) == NULLFILE)
- goto quit1;
- if (argc > 3 && tolower (argv[3][0]) == 'p')
- pauseonexit = 1;
- } else
- pauseonexit = 1;
-
- while (resp != -1) {
- switch (resp) {
- case 220: /* Sign-on banner; prompt for and send USER command */
- if ((cp = ftpcli_login (&ftp, sp->name)) == NULLCHAR) {
- if (argc > 2) {
- if (fgets (buf, LINELEN, fp1) == NULLCHAR)
- goto quit1;
- } else if (ftpgetline (sp, prmt, buf, LINELEN) == -1) {
- resp = -1;
- continue;
- }
- /* Send the command only if the user response
- * was non-null
- */
- if (buf[0] != '\n') {
- usprintf (control, "USER %s", buf);
- resp = getresp (&ftp, 200);
- } else {
- if (un != NULLCHAR) {
- usprintf (control, "USER %s\n", un);
- resp = getresp (&ftp, 200);
- } else {
- tputs ("No username sent\n");
- resp = 200; /* dummy */
- }
- }
- } else {
- usprintf (control, "USER %s\n", cp);
- free (cp);
- resp = getresp (&ftp, 200);
- }
- break;
- case 331:
- if (ftp.password == NULLCHAR) {
- /* turn off echo */
- if (argc > 2) {
- if (fgets (buf, LINELEN, fp1) == NULLCHAR)
- goto quit1;
- } else {
- sp->ttystate.echo = 0;
- if (ftpgetline (sp, "Password: ", buf, LINELEN) == -1) {
- resp = -1;
- continue;
- }
- tputc ('\n');
- /* Turn echo back on */
- sp->ttystate.echo = 1;
- }
- /* Send the command only if the user response
- * was non-null
- */
- if (buf[0] != '\n') {
- usprintf (control, "PASS %s", buf);
- resp = getresp (&ftp, 200);
- } else {
- tputs ("Password must be provided.\nLogin failed.\n");
- resp = 200; /* dummy */
- }
- } else {
- usprintf (control, "PASS %s\n", ftp.password);
- resp = getresp (&ftp, 200);
- free (ftp.password);
- ftp.password = NULLCHAR; /* clean up */
- }
- break;
- case 230: /* Successful login */
- /* Find out what type of system we're talking to */
- tputs ("ftp> syst\n");
- usprintf (control, "SYST\n");
- resp = getresp (&ftp, 200);
- break;
- case 215: /* Response to SYST command */
- cp = strchr (ftp.line, ' ');
- if (cp != NULLCHAR && strnicmp (cp + 1, System, strlen (System)) == 0) {
- ftp.type = IMAGE_TYPE;
- tputs ("Defaulting to binary mode\n");
- }
- resp = 200; /* dummy */
- break;
- #ifdef notyet
- case 399: /* Encrypted password login */
- if (ftp.password == NULLCHAR) {
- if (ftpgetline (sp, "Key ? --> ", buf, LINELEN) == -1) {
- resp = -1;
- continue;
- }
- /* Send the command only if the user response
- * was non-null
- */
- if (buf[0] != '\n') {
- cp = strchr (ftp.line, ':');
- cp += 2;
- /*
- epass(htol(cp),buf,l);
- */
- l[16] = '\0';
- free (ftp.line);
- ftp.line = NULLCHAR;
- usprintf (control, "PASS %s\n", l);
- resp = getresp (&ftp, 200);
- } else {
- tputs ("Password must be provided.\nLogin failed.\n");
- resp = 200; /* dummy */
- }
- } else {
- cp = strchr (ftp.line, ':');
- cp += 2;
- /*
- epass(htol(cp),ftp.password,l);
- */
- l[16] = '\0';
- free (ftp.line);
- ftp.line = NULLCHAR;
- usprintf (control, "PASS %s\n", l);
- resp = getresp (&ftp, 200);
- free (ftp.password);
- ftp.password = NULLCHAR; /* clean up */
- }
- break;
- #endif
- default: /* Test the control channel first */
- if (sockstate (control) == NULLCHAR) {
- resp = -1;
- break;
- }
- if (argc > 2) {
- if (fgets (buf, LINELEN, fp1) == NULLCHAR)
- goto quit1;
- } else if (ftpgetline (sp, "ftp> ", buf, LINELEN) == -1) {
- resp = -1;
- continue;
- }
- /* Copy because cmdparse modifies the original */
- bufsav = strdup (buf);
- if ((resp = cmdparse (Ftpcmds, buf, &ftp)) != -1) {
- /* Valid command, free buffer and get another */
- free (bufsav);
- } else {
- /* Not a local cmd, send to remote server */
- usputs (control, bufsav);
- free (bufsav);
-
- /* Enable display of server response */
- vsave = ftp.verbose;
- ftp.verbose = V_NORMAL;
- resp = getresp (&ftp, 200);
- ftp.verbose = (int16) vsave;
- }
- }
- }
- quit1: free (buf);
- quit: cp = sockerr (control);
- tprintf ("FTP session %u closed: %s\n", (unsigned) (sp - Sessions),
- cp != NULLCHAR ? cp : "EOF");
-
- if (ftp.fp != NULLFILE && ftp.fp != stdout)
- (void) fclose (ftp.fp);
- if (ftp.data != -1)
- close_s (ftp.data);
- if (ftp.control != -1)
- close_s (ftp.control);
- if (pauseonexit)
- (void) keywait (NULLCHAR, 1);
- if (fp1 != NULLFILE)
- (void) fclose (fp1);
- if (ftp.session != NULLSESSION)
- freesession (ftp.session);
- free_dirs (&dirs);
- return 0;
- }
-
-
- /* Control verbosity level */
- static int
- doverbose (int argc, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
-
- if ((ftp = (struct ftpcli *) p) == NULLFTP)
- return -1;
- return setshort (&ftp->verbose, "Verbose", argc, argv);
- }
-
-
- /* Enable/disable command batching */
- static int
- dobatch (int argc, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
-
- if ((ftp = (struct ftpcli *) p) == NULLFTP)
- return -1;
- return setbool (&ftp->batch, "Command batching", argc, argv);
- }
-
-
- /* Enable/disable update flag */
- static int
- doftpupdate (int argc, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
-
- if ((ftp = (struct ftpcli *) p) == NULLFTP)
- return -1;
- return setbool (&ftp->update, "Update with MD5", argc, argv);
- }
-
-
- /* Set verbosity to high (convenience command) */
- static int
- dohash (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
- {
- register struct ftpcli *ftp;
-
- if ((ftp = (struct ftpcli *) p) == NULLFTP)
- return -1;
- tputs ("Hash Printing ");
- if (ftp->verbose == V_HASH) {
- ftp->verbose = V_HASH + 1;
- tputs ("Off\n");
- } else {
- tputs ("On\n");
- ftp->verbose = V_HASH;
- }
- return 0;
- }
-
-
- /* Close session */
- static int
- doquit (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
- {
- register struct ftpcli *ftp;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP)
- return -1;
- usprintf (ftp->control, "QUIT\n");
- (void) getresp (ftp, 200); /* Get the closing message */
- (void) getresp (ftp, 200); /* Wait for the server to close */
- /* prevent spurious retry caused by "error" return */
- ftp->state = EXITING_STATE;
- return -1;
- }
-
-
- #ifdef LZW
- static int
- synclzw (register struct ftpcli *ftp)
- {
- int retval;
-
- usprintf (ftp->control, "XLZW %d %d\n", Lzwbits, Lzwmode);
- retval = getresp (ftp, 200);
- if (retval >= 200 && retval < 300) {
- ftp->lzwbits = Lzwbits;
- ftp->lzwmode = Lzwmode;
- }
- return retval;
- }
-
-
- /* Toggle LZW compressed streams mode on */
- static int
- doftplzw (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
- {
- register struct ftpcli *ftp;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP)
- return -1;
- ftp->lzw ^= 1;
- tprintf ("200 Client LZW o%s\n", (ftp->lzw) ? "n" : "ff");
- return (200);
- }
-
- #endif
-
-
- /* Rename remote file */
- static int
- doftprename (int argc OPTIONAL, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
- int retval;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP)
- return -1;
- usprintf (ftp->control, "RNFR %s\n", argv[1]);
- retval = getresp (ftp, 350);
-
- if (retval != 350)
- return (retval);
- usprintf (ftp->control, "RNTO %s\n", argv[2]);
- return (getresp (ftp, 200));
- }
-
-
- /* Rename local file */
- static int
- dolrename (int argc OPTIONAL, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
- char fname1[128];
- char fname2[128];
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP)
- return -1;
- strncpy (fname1, make_fname (ftp->curdirs->dir, argv[1]), 128);
- strncpy (fname2, make_fname (ftp->curdirs->dir, argv[2]), 128);
- if (rename (fname1, fname2) == -1)
- tprintf ("Can't rename: %s\n", SYS_ERRLIST(errno));
- else
- tprintf ("Local file renamed to '%s'\n", fname2);
- return 0;
-
- }
-
-
- static int
- txlate (int argc OPTIONAL, char *argv[], void *p, const char *substr, int parm)
- {
- register struct ftpcli *ftp;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP)
- return -1;
- usprintf (ftp->control, "%s %s\n", substr, (parm) ? argv[1] : "");
- return getresp (ftp, 200);
- }
-
-
- /* Pass PWD to server - included here to allow cmd to be viewed in help list */
- static int
- dopwd (int argc, char *argv[], void *p)
- {
- return (txlate (argc, argv, p, "PWD", 0));
- }
-
-
- /* Translate 'cd' to 'cwd' for convenience */
- static int
- doftpcd (int argc, char *argv[], void *p)
- {
- if (argc == 1)
- return (dopwd (argc, argv, p));
- return (txlate (argc, argv, p, "CWD", 1));
- }
-
-
- /* Pass CDUP to server - included here to allow cmd to be viewed in help list */
- static int
- doftpcdup (int argc, char *argv[], void *p)
- {
- return (txlate (argc, argv, p, "CDUP", 0));
- }
-
-
- /* Translate 'del' to 'dele' for convenience */
- static int
- doftpdel (int argc, char *argv[], void *p)
- {
- return (txlate (argc, argv, p, "DELE", 1));
- }
-
-
- /* Translate 'mkdir' to 'xmkd' for convenience */
- static int
- domkdir (int argc, char *argv[], void *p)
- {
- return (txlate (argc, argv, p, "XMKD", 1));
- }
-
-
- /* Translate 'rmdir' to 'xrmd' for convenience */
- static int
- dormdir (int argc, char *argv[], void *p)
- {
- return (txlate (argc, argv, p, "XRMD", 1));
- }
-
-
- static int
- dobinary (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
- {
- char *args[2];
- char buf[2];
-
- strcpy (buf, "I");
- args[1] = buf;
- return dotype (2, args, p);
- }
-
-
- static int
- doascii (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
- {
- char *args[2];
- char buf[2];
-
- strcpy (buf, "A");
- args[1] = buf;
- return dotype (2, args, p);
- }
-
-
- /* Handle "type" command from user */
- static int
- dotype (int argc, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP)
- return -1;
- if (argc < 2) {
- switch (ftp->type) {
- case IMAGE_TYPE:
- tputs ("Image\n");
- break;
- case ASCII_TYPE:
- tputs ("Ascii\n");
- break;
- case LOGICAL_TYPE:
- tprintf ("Logical bytesize %u\n", ftp->logbsize);
- break;
- default:
- break;
- }
- return 0;
- }
- switch (*argv[1]) {
- case 'i':
- case 'I':
- case 'b':
- case 'B':
- ftp->type = IMAGE_TYPE;
- break;
- case 'a':
- case 'A':
- ftp->type = ASCII_TYPE;
- break;
- case 'L':
- case 'l':
- ftp->type = LOGICAL_TYPE;
- ftp->logbsize = atoi (argv[2]);
- break;
- default:
- tprintf ("Invalid type %s\n", argv[1]);
- return 1;
- }
- return 0;
- }
-
-
- /* Handle "ftype" command */
- int
- doftype (int argc, char *argv[], void *p OPTIONAL)
- {
- if (argc < 2) {
- tputs ("Ftp initial TYPE is ");
- switch (Ftp_type) {
- case IMAGE_TYPE:
- tputs ("Image\n");
- break;
- case ASCII_TYPE:
- tputs ("Ascii\n");
- break;
- case LOGICAL_TYPE:
- tprintf ("Logical bytesize %u\n", Ftp_logbsize);
- break;
- default:
- break;
- }
- return 0;
- }
- switch (*argv[1]) {
- case 'i':
- case 'I':
- case 'b':
- case 'B':
- Ftp_type = IMAGE_TYPE;
- break;
- case 'a':
- case 'A':
- Ftp_type = ASCII_TYPE;
- break;
- case 'L':
- case 'l':
- if (argc < 3) {
- tprintf ("requires a bytesize parameter\nUsage: ftype logical <size>\n");
- return 1;
- }
- Ftp_type = LOGICAL_TYPE;
- Ftp_logbsize = atoi (argv[2]);
- break;
- default:
- tprintf ("Invalid type %s\n", argv[1]);
- return 1;
- }
- return 0;
- }
-
-
- /* View added to jnos1.08 by Simon G1FHY _ mod by Paul@wolf.demon.co.uk */
- /* Start view transfer. Syntax: view <remote name> */
- static int
- doftpview (int argc OPTIONAL, char *argv[], void *p)
- {
- char *remotename;
- register struct ftpcli *ftp;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- remotename = argv[1];
-
- (void) getsub (ftp, "RETR", remotename, NULLCHAR);
- return 0;
- }
-
-
- /* Start receive transfer. Syntax: get <remote name> [<local name>] */
- static int
- doget (int argc, char *argv[], void *p)
- {
- char *remotename, *localname;
- register struct ftpcli *ftp;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- remotename = argv[1];
- if (argc < 3)
- localname = remotename;
- else
- localname = argv[2];
-
- if (!ftp->update || compsub (ftp, localname, remotename) != 0)
- (void) getsub (ftp, "RETR", remotename, localname);
- return 0;
- }
-
-
- /* Get a collection of files */
- static int
- domget (int argc, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
- FILE *files, *filel;
- char tmpname[80];
- char *buf, *local;
- #ifdef MSDOS
- char *c;
- #endif
- int i;
- #ifdef MSDOS
- int inlist;
- #endif
- long r;
-
- if ((ftp = (struct ftpcli *) p) == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- (void) tmpnam (tmpname);
- buf = mallocw (FTPDIRBUF);
- ftp->state = RECEIVING_STATE;
- for (i = 1; i < argc; i++) {
- if (argv[i][0] == '@') {
- #ifdef MSDOS
- inlist = 1;
- #endif
- if ((filel = fopen (make_fname (ftp->curdirs->dir, &argv[i][1]), "r")) == NULLFILE) {
- tprintf ("Can't open listfile: %s\n", &argv[i][1]);
- continue;
- }
- if ((files = fopen (tmpname, "w")) == NULLFILE) {
- tprintf ("Can't open tempfile: %s\n", tmpname);
- continue;
- }
- while (fgets (buf, FTPDIRBUF, filel) != NULLCHAR)
- fputs (buf, files);
-
- (void) fclose (files);
- (void) fclose (filel);
- if ((files = fopen (tmpname, "r")) == NULLFILE) {
- tprintf ("Can't open tempfile: %s\n", tmpname);
- continue;
- }
- } else {
- #ifdef MSDOS
- inlist = 0;
- #endif
- r = getsub (ftp, "NLST", argv[i], tmpname);
- if (ftp->abort)
- break; /* Aborted */
- if (r == -1 || (files = fopen (tmpname, "r")) == NULLFILE) {
- tprintf ("Can't NLST %s\n", argv[i]);
- unlink (tmpname);
- continue;
- }
- }
- /* The tmp file now contains a list of the remote files, so
- * go get 'em. Break out if the user signals an abort.
- */
- while (fgets (buf, FTPDIRBUF, files) != NULLCHAR) {
- rip (buf);
- local = strdup (buf);
- #ifdef MSDOS
- if (inlist) {
- strrev (local);
- (void) strtok (local, "\\/[]<>,?#~()&%");
- strrev (local);
- }
- if ((c = strstr (local, ".")) != NULLCHAR) {
- c++;
- c = strtok (c, "."); /* remove 2nd period if any*/
- }
- #endif
- if (!ftp->update || compsub (ftp, buf, buf) != 0)
- (void) getsub (ftp, "RETR", buf, local);
- usflush (ftp->control);
- free (local);
- if (ftp->abort) {
- /* User abort */
- ftp->abort = 0;
- (void) fclose (files);
- unlink (tmpname);
- free (buf);
- ftp->state = COMMAND_STATE;
- return 1;
- }
- }
- (void) fclose (files);
- unlink (tmpname);
- }
- free (buf);
- ftp->state = COMMAND_STATE;
- ftp->abort = 0;
- return 0;
- }
-
-
- /* Resume interrupted file transfer. Syntax: resume <remote name> [<local name>] */
- static int
- doresume (int argc, char *argv[], void *p)
- {
- char *remotename, *localname;
- register struct ftpcli *ftp;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- remotename = argv[1];
- if (argc < 3)
- localname = remotename;
- else
- localname = argv[2];
-
- (void) getsub (ftp, "RSME", remotename, localname);
- return 0;
- }
-
- /* List remote directory. Syntax: dir <remote files> [<local name>] */
- static int
- dolist (int argc, char *argv[], void *p)
- {
- char *remotename, *localname;
- register struct ftpcli *ftp;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- remotename = argv[1];
- if (argc > 2)
- localname = argv[2];
- else
- localname = NULLCHAR;
-
- (void) getsub (ftp, "LIST", remotename, localname);
- return 0;
- }
-
-
- /* Remote directory list, short form. Syntax: ls <remote files> [<local name>] */
- static int
- dols (int argc, char *argv[], void *p)
- {
- char *remotename, *localname;
- register struct ftpcli *ftp;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- remotename = argv[1];
- if (argc > 2)
- localname = argv[2];
- else
- localname = NULLCHAR;
-
- (void) getsub (ftp, "NLST", remotename, localname);
- return 0;
- }
-
-
- static int
- domd5 (int argc OPTIONAL, char *argv[], void *p)
- {
- char *remotename;
- register struct ftpcli *ftp;
- int control;
- int resp;
- int typewait = 0;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- control = ftp->control;
- remotename = argv[1];
- if (ftp->typesent != ftp->type) {
- switch (ftp->type) {
- case ASCII_TYPE:
- usprintf (control, "TYPE A\n");
- break;
- case IMAGE_TYPE:
- usprintf (control, "TYPE I\n");
- break;
- case LOGICAL_TYPE:
- usprintf (control, "TYPE L %d\n", ftp->logbsize);
- break;
- default:
- break;
- }
- ftp->typesent = ftp->type;
- if (!ftp->batch) {
- resp = getresp (ftp, 200);
- if (resp == -1 || resp > 299)
- goto failure;
- } else
- typewait = 1;
-
- }
- usprintf (control, "XMD5 %s\n", remotename);
- if (typewait)
- (void) getresp (ftp, 200);
- (void) getresp (ftp, 200);
- failure:
- return 0;
- }
-
-
- static int
- docompare (int argc, char *argv[], void *p)
- {
- char *remotename, *localname;
- register struct ftpcli *ftp;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- remotename = argv[1];
- if (argc > 2)
- localname = argv[2];
- else
- localname = remotename;
-
- if (compsub (ftp, localname, remotename) == 0)
- tputs ("Same\n");
- else
- tputs ("Different\n");
- return 0;
- }
-
-
- /* Compare a collection of files */
- static int
- domcompare (int argc, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
- FILE *files;
- char *buf;
- int i;
- long r;
- char tmpname[80];
-
- if ((ftp = (struct ftpcli *) p) == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- (void) tmpnam (tmpname);
- buf = mallocw (FTPDIRBUF);
- ftp->state = RECEIVING_STATE;
- for (i = 1; i < argc; i++) {
- r = getsub (ftp, "NLST", argv[i], tmpname);
- if (ftp->abort)
- break; /* Aborted */
- if (r == -1 || (files = fopen (tmpname, "r")) == NULLFILE) {
- tprintf ("Can't NLST %s\n", argv[i]);
- unlink (tmpname);
- continue;
- }
- /* The tmp file now contains a list of the remote files, so
- * go get 'em. Break out if the user signals an abort.
- */
- while (fgets (buf, FTPDIRBUF, files) != NULLCHAR) {
- rip (buf);
- if (compsub (ftp, buf, buf) == 0)
- tprintf ("%s - Same\n", buf);
- else
- tprintf ("%s - Different\n", buf);
-
- if (ftp->abort) {
- /* User abort */
- ftp->abort = 0;
- (void) fclose (files);
- unlink (tmpname);
- free (buf);
- ftp->state = COMMAND_STATE;
- return 1;
- }
- }
- (void) fclose (files);
- unlink (tmpname);
- }
- free (buf);
- ftp->state = COMMAND_STATE;
- ftp->abort = 0;
- return 0;
- }
-
-
- /* Common subroutine to compare a local with a remote file
- * Return 1 if files are different, 0 if they are the same
- */
- static int
- compsub (struct ftpcli *ftp, char *localname, char *remotename)
- {
- char const *mode = NULLCHAR;
- char *cp;
- FILE *fp;
- int control;
- int resp, i;
- int typewait = 0;
- char remhash[16];
- char lochash[16];
-
- control = ftp->control;
-
- switch (ftp->type) {
- case IMAGE_TYPE:
- case LOGICAL_TYPE:
- mode = READ_BINARY;
- break;
- case ASCII_TYPE:
- default:
- mode = READ_TEXT;
- break;
- }
- if ((fp = fopen (make_fname (ftp->curdirs->dir, localname), mode)) == NULLFILE) {
- tprintf ("Can't read local file %s\n", make_fname (ftp->curdirs->dir, localname));
- return 1;
- }
- if (ftp->typesent != ftp->type) {
- switch (ftp->type) {
- case ASCII_TYPE:
- usprintf (control, "TYPE A\n");
- break;
- case IMAGE_TYPE:
- usprintf (control, "TYPE I\n");
- break;
- case LOGICAL_TYPE:
- usprintf (control, "TYPE L %d\n", ftp->logbsize);
- break;
- default:
- break;
- }
- ftp->typesent = ftp->type;
- if (!ftp->batch) {
- resp = getresp (ftp, 200);
- if (resp == -1 || resp > 299)
- goto failure;
- } else
- typewait = 1;
- }
- usprintf (control, "XMD5 %s\n", remotename);
- /* Try to overlap the two MD5 operations */
- (void) md5hash (fp, lochash, ftp->type == ASCII_TYPE);
- (void) fclose (fp);
- if (typewait && (resp = getresp (ftp, 200)) > 299)
- goto failure;
- if ((resp = getresp (ftp, 200)) > 299) {
- if (resp == 500)
- ftp->update = 0; /* XMD5 not supported */
- goto failure;
- }
- if ((cp = strchr (ftp->line, ' ')) == NULLCHAR) {
- tputs ("Error in response\n");
- goto failure;
- }
- /* Convert ascii/hex back to binary */
- (void) readhex (remhash, cp, sizeof (remhash));
- if (ftp->verbose > 1) {
- tputs ("Loc ");
- for (i = 0; i < (int) sizeof (lochash); i++)
- tprintf ("%02x", lochash[i] & 0xff);
- tprintf (" %s\n", make_fname (ftp->curdirs->dir, localname));
- }
- if (memcmp (lochash, remhash, sizeof (remhash)) == 0)
- return 0;
- else
- return 1;
- failure:
- return 1;
- }
-
-
- /* Common code to LIST/NLST/RETR/RSME and mget
- * Returns number of bytes received if successful
- * Returns -1 on error
- */
- static long
- getsub (register struct ftpcli *ftp, const char *command, const char *remotename, char *localname)
- {
- unsigned long total;
- FILE *fp;
- int resp, i, control, savmode;
- char const *mode;
- struct sockaddr_in lsocket;
- struct sockaddr_in lcsocket;
- int32 startclk, rate;
- int vsave;
- int typewait = 0;
- int prevstate;
- unsigned long starting;
-
- if (ftp == NULLFTP)
- return -1;
- control = ftp->control;
- savmode = ftp->type;
- #ifdef __GNUC__
- mode = 0; /* semi-spurious warning */
- #endif
-
- switch (ftp->type) {
- case IMAGE_TYPE:
- case LOGICAL_TYPE:
- if (strcmp (command, "RSME") == 0)
- mode = APPEND_BINARY;
- else
- mode = WRITE_BINARY;
- break;
- default:
- case ASCII_TYPE:
- if (strcmp (command, "RSME") == 0)
- mode = APPEND_TEXT;
- else
- mode = WRITE_TEXT;
- break;
- }
- /* Open the file */
- if (localname == NULLCHAR) {
- fp = NULLFILE;
- } else if ((fp = fopen (make_fname (ftp->curdirs->dir, localname), mode)) == NULLFILE) {
- tprintf ("Can't write %s: %s\n", localname, SYS_ERRLIST(errno));
- return -1;
- }
- /* Open the data connection */
- ftp->data = socket (AF_INET, SOCK_STREAM, 0);
- (void) listen (ftp->data, 0); /* Accept only one connection */
- prevstate = ftp->state;
- ftp->state = RECEIVING_STATE;
-
- /* Send TYPE message, if necessary */
- if (strcmp (command, "LIST") == 0 || strcmp (command, "NLST") == 0) {
- /* Directory listings are always in ASCII */
- ftp->type = ASCII_TYPE;
- }
- if (ftp->typesent != ftp->type) {
- switch (ftp->type) {
- case ASCII_TYPE:
- usprintf (control, "TYPE A\n");
- break;
- case IMAGE_TYPE:
- usprintf (control, "TYPE I\n");
- break;
- case LOGICAL_TYPE:
- usprintf (control, "TYPE L %d\n", ftp->logbsize);
- break;
- default:
- break;
- }
- ftp->typesent = ftp->type;
- if (!ftp->batch) {
- resp = getresp (ftp, 200);
- if (resp == -1 || resp > 299)
- goto failure;
- } else
- typewait = 1;
- }
- /* Send the PORT message. Use the IP address
- * on the local end of our control connection.
- */
- i = SOCKSIZE;
- (void) getsockname (ftp->data, (char *) &lsocket, &i); /* Get port number */
- if (!i)
- goto failure;
- i = SOCKSIZE;
- (void) getsockname (ftp->control, (char *) &lcsocket, &i);
- if (!i)
- goto failure;
- lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
- sendport (control, &lsocket);
- if (!ftp->batch) {
- /* Get response to PORT command */
- resp = getresp (ftp, 200);
- if (resp == -1 || resp > 299)
- goto failure;
- }
- #ifdef LZW
- if (ftp->lzw && ftp->type == ASCII_TYPE) {
- int retval = 200;
-
- retval = synclzw (ftp);
- if (retval >= 200 && retval < 300)
- lzwinit (ftp->data, ftp->lzwbits, ftp->lzwmode);
- }
- #endif
-
- /* Generate the command to start the transfer */
- if (remotename != NULLCHAR)
- usprintf (control, "%s %s\n", command, remotename);
- else
- usprintf (control, "%s\n", command);
-
- if (ftp->batch) {
- /* Get response to TYPE command, if sent */
- if (typewait) {
- resp = getresp (ftp, 200);
- if (resp == -1 || resp > 299)
- goto failure;
- }
- /* Get response to PORT command */
- resp = getresp (ftp, 200);
- if (resp == -1 || resp > 299)
- goto failure;
- }
- /* Get the intermediate "150" response */
- resp = getresp (ftp, 100);
- if (resp == -1 || resp >= 400)
- goto failure;
-
- /* Wait for the server to open the data connection */
- (void) accept (ftp->data, NULLCHAR, (int *) NULL);
- startclk = msclock ();
-
- /* If output is to the screen, temporarily disable hash marking */
- vsave = ftp->verbose;
- if (vsave >= V_HASH && fp == NULLFILE)
- ftp->verbose = V_NORMAL;
- if (strcmp (command, "RSME") == 0) {
- if ((starting = getsize (fp)) == (unsigned long) -1)
- starting = 0L;
- usprintf (control, "%lu %lu\n", starting, checksum (fp, (long) starting));
- usflush (control);
- if (fp != NULLFILE)
- fseek (fp, (long) starting, SEEK_SET);
- }
- total = (unsigned long) recvfile (fp, ftp->data, ftp->type, (ftp->verbose >= V_HASH) ? ftp->verbose : 0);
- /* Immediately close the data connection; some servers (e.g., TOPS-10)
- * wait for the data connection to close completely before returning
- * the completion message on the control channel
- */
- close_s (ftp->data);
- ftp->data = -1;
-
- #ifdef CPM
- if (fp != NULLFILE && ftp->type == ASCII_TYPE)
- putc (CTLZ, fp);
- #endif
- if (fp != NULLFILE && fp != stdout)
- (void) fclose (fp);
- if (remotename == NULLCHAR)
- remotename = "";
- if (total == (unsigned long) -1) {
- tprintf ("%s %s: Error/abort during data transfer\n", command, remotename);
- } else if (ftp->verbose >= V_SHORT) {
- startclk = msclock () - startclk;
- rate = 0;
- if (startclk != 0) { /* Avoid divide-by-zero */
- if (total < 4294967L)
- rate = (long) ((total * 1000) / (uint32) startclk);
- else /* Avoid overflow */
- rate = (long) (total / (uint32) (startclk / 1000));
- }
- tprintf ("%s %s: %lu bytes in %lu sec (%lu/sec)\n",
- command, remotename, total, startclk / 1000, rate);
- }
- /* Get the "Sent" message */
- (void) getresp (ftp, 200);
-
- ftp->state = (char) prevstate;
- ftp->verbose = (int16) vsave;
- ftp->type = (char) savmode;
- return ((long) total);
-
- failure:
- /* Error, quit */
- if (fp != NULLFILE && fp != stdout)
- (void) fclose (fp);
- close_s (ftp->data);
- ftp->data = -1;
- ftp->state = (char) prevstate;
- ftp->type = (char) savmode;
- return -1;
- }
-
-
- /* Send a file. Syntax: put <local name> [<remote name>] */
- static int
- doput (int argc, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
- char *remotename, *localname;
-
- if ((ftp = (struct ftpcli *) p) == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- localname = argv[1];
- if (argc < 3)
- remotename = localname;
- else
- remotename = argv[2];
-
- if (!ftp->update || compsub (ftp, localname, remotename) != 0)
- (void) putsub (ftp, remotename, localname, (*argv[0] == 'a') ? 2 : 0);
- return 0;
- }
-
-
- /* Put a collection of files */
- static int
- domput (int argc, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
- FILE *files;
- int i;
- #if 0
- int j;
- #endif
- char tmpname[80];
- char *buf, *file;
-
- if ((ftp = (struct ftpcli *) p) == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- (void) tmpnam (tmpname);
- if ((files = fopen (tmpname, "w+")) == NULLFILE) {
- tputs ("Can't list local files\n");
- unlink (tmpname);
- return 1;
- }
- for (i = 1; i < argc; i++) {
- /* Use the path in the ftp client struct, since user may have done
- * a lcd command to change dir !
- */
- file = pathname (ftp->curdirs->dir, argv[i]);
- #if 0 /* was #ifdef MSDOS */
- /* Shift everything back one byte, pathname returns with a leading '/'! */
- for (j = 1; j <= strlen (file); j++)
- file[j - 1] = file[j];
- #endif
- (void) getdir (file, 0, files);
- free (file);
- }
-
- rewind (files);
- buf = mallocw (FTPDIRBUF);
- ftp->state = SENDING_STATE;
- while (fgets (buf, FTPDIRBUF, files) != NULLCHAR) {
- rip (buf);
- if (!ftp->update || compsub (ftp, buf, buf) != 0)
- (void) putsub (ftp, buf, buf, 0);
- if (ftp->abort)
- break; /* User abort */
- usflush (ftp->control);
- }
- (void) fclose (files);
- unlink (tmpname);
- free (buf);
- ftp->state = COMMAND_STATE;
- ftp->abort = 0;
- return 0;
- }
-
-
- /* Put a file, appending data to it - iw0cnb */
- static int
- dorput (int argc, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
- char *remotename, *localname;
-
- if ((ftp = (struct ftpcli *) p) == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- localname = argv[1];
- if (argc < 3)
- remotename = localname;
- else
- remotename = argv[2];
-
- (void) putsub (ftp, remotename, localname, 1);
- return 0;
- }
-
-
- /* Common code to put, mput.
- * Returns number of bytes sent if successful
- * Returns -1 on error
- */
- static long
- putsub (ftp, remotename, localname, putr)
- register struct ftpcli *ftp;
- char *remotename, *localname;
- int putr; /* Flag: 0 if standard put, 1 if put with resume, if 2 append */
- {
- char const *mode;
- int i, resp, control;
- unsigned long total;
- FILE *fp;
- struct sockaddr_in lsocket, lcsocket;
- int32 startclk, rate;
- int typewait = 0;
- int prevstate;
- char *line;
- unsigned long starting;
- unsigned long check, local_check;
-
- control = ftp->control;
- if (ftp->type == IMAGE_TYPE)
- mode = READ_BINARY;
- else
- mode = READ_TEXT;
-
- /* Open the file */
- if ((fp = fopen (make_fname (ftp->curdirs->dir, localname), mode)) == NULLFILE) {
- tprintf ("Can't read %s: %s\n", localname, SYS_ERRLIST(errno));
- return -1;
- }
- if (ftp->type == ASCII_TYPE && isbinary (fp)) {
- tprintf ("Warning: type is ASCII and %s appears to be binary\n", localname);
- }
- /* Open the data connection */
- ftp->data = socket (AF_INET, SOCK_STREAM, 0);
- (void) listen (ftp->data, 0);
- prevstate = ftp->state;
- ftp->state = SENDING_STATE;
-
- /* Send TYPE message, if necessary */
- if (ftp->typesent != ftp->type) {
- switch (ftp->type) {
- case ASCII_TYPE:
- usprintf (control, "TYPE A\n");
- break;
- case IMAGE_TYPE:
- usprintf (control, "TYPE I\n");
- break;
- case LOGICAL_TYPE:
- usprintf (control, "TYPE L %d\n", ftp->logbsize);
- break;
- default:
- break;
- }
- ftp->typesent = ftp->type;
-
- /* Get response to TYPE command */
- if (!ftp->batch) {
- resp = getresp (ftp, 200);
- if (resp == -1 || resp > 299) {
- goto failure;
- }
- } else
- typewait = 1;
- }
- /* Send the PORT message. Use the IP address
- * on the local end of our control connection.
- */
- i = SOCKSIZE;
- (void) getsockname (ftp->data, (char *) &lsocket, &i);
- if (!i)
- goto failure;
- i = SOCKSIZE;
- (void) getsockname (ftp->control, (char *) &lcsocket, &i);
- if (!i)
- goto failure;
- lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
- sendport (control, &lsocket);
- if (!ftp->batch) {
- /* Get response to PORT command */
- resp = getresp (ftp, 200);
- if (resp == -1 || resp > 299) {
- goto failure;
- }
- }
- #ifdef LZW
- if (ftp->lzw && ftp->type == ASCII_TYPE) {
- int retval = 200;
-
- retval = synclzw (ftp);
- if (retval >= 200 && retval < 300)
- lzwinit (ftp->data, ftp->lzwbits, ftp->lzwmode);
- }
- #endif
-
- /* Generate the command to start the transfer */
- if (putr == 1)
- usprintf (control, "RPUT %s\n", remotename);
- else if (putr == 2)
- usprintf (control, "APPE %s\n", remotename);
- else
- usprintf (control, "STOR %s\n", remotename);
-
- if (ftp->batch) {
- /* Get response to TYPE command, if sent */
- if (typewait) {
- resp = getresp (ftp, 200);
- if (resp == -1 || resp > 299) {
- goto failure;
- }
- }
- /* Get response to PORT command */
- resp = getresp (ftp, 200);
- if (resp == -1 || resp > 299) {
- goto failure;
- }
- }
- /* Get the intermediate "150" response */
- resp = getresp (ftp, 100);
- if (resp == -1 || resp >= 400) {
- goto failure;
- }
- /* Wait for the data connection to open. Otherwise the first
- * block of data would go out with the SYN, and this may confuse
- * some other TCPs
- */
- (void) accept (ftp->data, NULLCHAR, (int *) NULL);
-
- startclk = msclock ();
-
- if (putr == 1) { /* Wait for file offset and checksum */
- char *ctmp;
- line = mallocw (40);
- if (recvline (control, (unsigned char *) line, 40) == -1) {
- free (line);
- goto failure;
- }
- starting = (unsigned long) atol (line);
- ctmp = strchr (line, ' ');
- if (ctmp != NULLCHAR)
- check = (unsigned long) atol (ctmp);
- else
- check = 0;
- free (line);
- local_check = checksum (fp, (long) starting);
- if (ftp->verbose >= V_HASH)
- tprintf ("Remote checksum: %lu - Local checksum: %lu - Offset: %lu\n", check, local_check, starting);
- check -= local_check;
- if (check != 0) {
- tprintf ("Can't send %s: files are different\n", localname);
- (void) shutdown (ftp->data, 1);
- (void) getresp (ftp, 200);
- goto failure;
- }
- }
- total = (unsigned long) sendfile (fp, ftp->data, ftp->type, (ftp->verbose >= V_HASH) ? ftp->verbose : 0);
- close_s (ftp->data);
- ftp->data = -1;
- (void) fclose (fp);
-
- /* Wait for control channel ack before calculating transfer time;
- * this accounts for transmitted data in the pipe.
- */
- (void) getresp (ftp, 200);
-
- if (total == (unsigned long) -1) {
- tprintf ("STOR %s: Error/abort during data transfer\n", remotename);
- } else if (ftp->verbose >= V_SHORT) {
- startclk = msclock () - startclk;
- rate = 0;
- if (startclk != 0) { /* Avoid divide-by-zero */
- if (total < 4294967L)
- rate = (long) ((total * 1000) / (uint32) startclk);
- else /* Avoid overflow */
- rate = (long) (total / (uint32)(startclk / 1000));
- }
- tprintf ("STOR %s: %lu bytes in %lu sec (%lu/sec)\n",
- remotename, total, startclk / 1000, rate);
- }
- ftp->state = (char) prevstate;
- return ((long) total);
-
- failure:
- /* Error, quit */
- (void) fclose (fp);
- close_s (ftp->data);
- ftp->data = -1;
- ftp->state = (char) prevstate;
- return -1;
- }
-
-
- /* Abort a GET or PUT operation in progress. Note: this will leave
- * the partial file on the local or remote system
- */
- int
- doabort (int argc, char *argv[], void *p)
- {
- register struct session *sp;
- register struct ftpcli *ftp;
-
- sp = (struct session *) p;
- if (sp == NULLSESSION)
- return -1;
-
- /* Default is the current session, but it can be overridden with
- * an argument.
- */
- if (argc > 1)
- sp = sessptr (argv[1]);
-
- if (sp == NULLSESSION || sp->type != FTP) {
- tputs ("Not an active FTP session\n");
- return 1;
- }
- ftp = sp->cb.ftp;
- switch (ftp->state) {
- case COMMAND_STATE:
- tputs ("No active transfer\n");
- return 1;
- case SENDING_STATE:
- /* Send a premature EOF.
- * Unfortunately we can't just reset the connection
- * since the remote side might end up waiting forever
- * for us to send something.
- */
- (void) shutdown (ftp->data, 1); /* Note fall-thru */
- ftp->abort = 1;
- break;
- case RECEIVING_STATE:
- /* Just blow away the receive socket */
- (void) shutdown (ftp->data, 2); /* Note fall-thru */
- ftp->abort = 1;
- break;
- default:
- break;
- }
- return 0;
- }
-
-
- /* send PORT message */
- static void
- sendport (int s, struct sockaddr_in *thesocket)
- {
- /* Send PORT a,a,a,a,p,p message */
- usprintf (s, "PORT %u,%u,%u,%u,%u,%u\n",
- hibyte (hiword (thesocket->sin_addr.s_addr)),
- lobyte (hiword (thesocket->sin_addr.s_addr)),
- hibyte (loword (thesocket->sin_addr.s_addr)),
- lobyte (loword (thesocket->sin_addr.s_addr)),
- hibyte (thesocket->sin_port),
- lobyte (thesocket->sin_port));
- }
-
-
- /* Wait for, read and display response from FTP server. Return the result code.
- */
- static int
- getresp (ftp, mincode)
- struct ftpcli *ftp;
- int mincode; /* Keep reading until at least this code comes back */
- {
- int rval;
-
- usflush (ftp->control);
- for (;;) {
- /* Get line */
- if (recvline (ftp->control, (unsigned char *) ftp->line, LINELEN) == -1) {
- rval = -1;
- break;
- }
- rip (ftp->line);/* Remove cr/lf */
- rval = atoi (ftp->line);
- if (rval >= 400 || ftp->verbose >= V_NORMAL)
- tprintf ("%s\n", ftp->line); /* Display to user */
-
- /* Messages with dashes are continued */
- if (ftp->line[3] != '-' && rval >= mincode)
- break;
- }
- return rval;
- }
-
-
- /* Issue a prompt and read a line from the user */
- static int
- ftpgetline (struct session *sp, const char *prompt, char *buf, int n)
- {
- /* If there's something already there, don't issue prompt */
- if (socklen (sp->input, 0) == 0)
- tputs (prompt);
-
- usflush (sp->output);
- return recvline (sp->input, (unsigned char *) buf, (unsigned) n);
- }
-
-
- /* Attempt to log in the user whose name is in ftp->username and password
- * in pass
- */
- static char *
- ftpcli_login (struct ftpcli *ftp, char *host)
- {
- char buf[80], *cp = NULLCHAR, *cp1;
- FILE *fp;
-
-
- if ((fp = fopen (Hostfile, "r")) == NULLFILE)
- return NULLCHAR;
-
- while ((void) fgets (buf, sizeof (buf), fp), !feof (fp)) {
- buf[strlen (buf) - 1] = '\0'; /* Nuke the newline */
- if (buf[0] == '#')
- continue; /* Comment */
- if ((cp = strchr (buf, ' ')) == NULLCHAR)
- /* Bogus entry */
- continue;
- *cp++ = '\0'; /* Now points to user name */
- if (strcmp (host, buf) == 0)
- break; /* Found host name */
- }
- if (feof (fp)) {
- /* User name not found in file */
- (void) fclose (fp);
- return NULLCHAR;
- }
- (void) fclose (fp);
- /* Look for space after user field in file */
- cp = skipwhite (cp);
- if ((cp1 = strpbrk (cp, " \t")) == NULLCHAR)
- /* if not there then we'll prompt */
- ftp->password = NULLCHAR;
- else
- *cp1++ = '\0'; /* Now points to password */
- cp1 = skipwhite (cp1);
- ftp->password = (strcmp (cp, "*")) ? strdup (cp1) : strdup ("anonymous");
- return strdup (cp);
- }
-
-
- int
- dolcd (int argc, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- if (argc > 1) {
- if (!dir_ok (argv[1], ftp->curdirs)) {
- tprintf ("Invalid Drive/Directory - %s\n", argv[1]);
- return 1;
- }
- }
- tprintf ("Local Directory - %s\n", ftp->curdirs->dir);
- return 0;
- }
-
-
- #ifdef ALLSESSIONS
- int
- doldir (int argc, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
- char **margv;
-
- margv = (char **) callocw (2, sizeof (char *));
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- tputc ('\n');
- if (argc == 1)
- margv[1] = strdup (ftp->curdirs->dir);
- else
- margv[1] = strdup (make_dir_path (argc, argv[1], ftp->curdirs->dir));
- (void) dodir (2, margv, p);
- free (margv[1]);
- free (margv);
- tputc ('\n');
- return 0;
- }
-
- #endif
-
-
- int
- dolmkdir (int argc OPTIONAL, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
- char *buf;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- /* undosify(argv[1]); done in make_fname */
- buf = strdup (make_fname (ftp->curdirs->dir, argv[1]));
- if (mkdir (buf, 0777) == -1)
- tprintf ("Can't make %s: %s\n", buf, SYS_ERRLIST(errno));
- else
- tprintf ("Directory %s Created\n", buf);
- free (buf);
- return 0;
- }
-
-
- int
- dolrmdir (int argc OPTIONAL, char *argv[], void *p)
- {
- register struct ftpcli *ftp;
- char *buf;
-
- ftp = (struct ftpcli *) p;
- if (ftp == NULLFTP) {
- tputs (Notsess);
- return 1;
- }
- buf = strdup (make_fname (ftp->curdirs->dir, argv[1]));
- if (rmdir (buf) == -1)
- tprintf ("Can't remove %s: %s\n", buf, SYS_ERRLIST(errno));
- else
- tprintf ("Directory %s Removed\n", buf);
- free (buf);
- return 0;
- }
-
- #endif
-